/* (C) C.D.F. Miller, Heriot-Watt University, March 1984
 *
 *	Permission is hereby given to reproduce or modify this
 *	software freely, provided that this notice be retained,
 *	and that no use be made of the software for commercial
 *	purposes without the express written permission of the
 *	author.
 */

#include	<lbl.h>
#include	<ctype.h>
#include        <stdlib.h>
#include        <bsd/string.h>
#include        <err.h>
#include        <sysexits.h>
#include        "build.h"
#include        "find.h"

extern char *def_format;
extern char *filename;
extern long fileline;
extern std::list<Type> typehead;

static void *alloc(unsigned long nbytes);
static void *
alloc(unsigned long nbytes)
{
	void *ptr = malloc(nbytes);

	if (ptr == NULL)
		errx(EX_OSERR, "%sran out of memory space", maybe_loc());
	return ptr;
}

char   *
copy(char *str)
{
	char   *s = (char *)alloc(strlen(str) + 1);

	strlcpy(s, str, strlen(str) + 1);
	return s;
}

void
addlbl(char *lbltype, char *lbllevel, char *lblname)
{
	Type *tp = findtype(lbltype, 1);
	Label *last_next;
	int bottom;
	int indx;

	if (!isdigit(lbllevel[0])) {
		warnx("%snon-numeric index level", maybe_loc());
		return;
	}
	if ((bottom = atoi(lbllevel)) <= 0 || bottom > NLEVELS) {
		warnx("%sindex level must be in range 1-%u", maybe_loc(),
		      NLEVELS);
		return;
	}
	bottom--;

	++(tp->t_levels[bottom]);
	for (indx = bottom + 1; indx < NLEVELS; indx++)
		tp->t_levels[indx] = 0;

	if (strcmp(lblname, "*") != 0) {
		Label *lp;

		lp = typeFindlabel(tp, lblname);

		if (lp != NULL) {
			warnx("%sredefinition of %s ignored", maybe_loc(),
			      lblname);
			return;
		}
		lp = (Label *) alloc(sizeof(Label));

		lp->l_name = copy(lblname);
		lp->l_type = tp;
		for (indx = 0; indx < bottom; indx++)
			lp->l_levels[indx] = tp->t_levels[indx];
		lp->l_levels[bottom] = tp->t_levels[bottom];
		lp->l_bottom = bottom;
		lp->l_file = filename;
		lp->l_line = fileline;
		/*
		 * Add to end of list, so that verbose listing comes out in
		 * order
		 */
		if (LIST_EMPTY(&(tp->labelhead)))
			LIST_INSERT_HEAD(&(tp->labelhead), lp, link);
		else {
			Label *last;

			last = LIST_FIRST(&(tp->labelhead));
			last_next = LIST_NEXT(last, link);
			while (last_next != NULL) {
				last = last_next;
				last_next = LIST_NEXT(last, link);
			}
			LIST_INSERT_AFTER(last, lp, link);
		}
	}
}

Type   *
addtype(char *name)
{
	Type *tp = (Type *) alloc(sizeof(Type));
	us int indx;

	tp->t_name = copy(name);
	for (indx = 0; indx < NLEVELS; indx++)
		tp->t_levels[indx] = 0;
	tp->t_format = def_format;
	LIST_INIT(&(tp->labelhead));
	LIST_INSERT_HEAD(&typehead, tp, link);
	return tp;
}
